package de.mnit.schnipsel.swt.editor.basis;

import org.eclipse.swt.SWT;
import org.eclipse.swt.custom.StyleRange;
import org.eclipse.swt.graphics.FontData;
import org.eclipse.swt.graphics.Point;
import org.eclipse.swt.widgets.Display;

import de.mnit.basis.daten.MN;
import de.mnit.basis.daten.Mathe;
import de.mnit.basis.daten.WandleFolge;
import de.mnit.basis.daten.struktur.S_Folge;
import de.mnit.basis.daten.struktur.liste.Liste;
import de.mnit.basis.daten.struktur.liste.S_Liste;
import de.mnit.basis.daten.struktur.schluessel.S_SchluesselListe;
import de.mnit.basis.daten.struktur.schluessel.SchluesselListe;
import de.mnit.basis.fehler.Fehler;
import de.mnit.basis.swt.element.steuer.rollbar.gruppe.bild.SWT_TextEditor;
import de.mnit.basis.swt.konstant.SWT_SCHRIFT;
import de.mnit.basis.swt.konstant.SWT_SCHRIFTSTIL;
import de.mnit.basis.swt.statisch.SchriftManager;
import de.mnit.basis.sys.Ausgabe;
import de.mnit.basis.sys.event.A_HatZuhoerer;
import de.mnit.basis.sys.event.S_Zuhoerer;

/**
 * @author Michael Nitsche
 * 28.06.2010	Erstellt
 */
public class TE_Format extends A_HatZuhoerer<TE_Format> {

	private final String E_AENDERUNG="aenderung";
	private final String E_KNOPF_DEAKTIV="knopf_deaktiv";
	private final SWT_TextEditor editor;
	private final S_SchluesselListe<TE_STYLE, S_TE_SetStyle> styles;
	private enum SETZEN { ABFRAGE, SETZEN, AUFHEBEN, WECHSELN };


	public TE_Format(SWT_TextEditor te) {
		editor=te;
		styles=iRegistrieren();
	}


	// EVENT

	public void eGeaendert(S_Zuhoerer<?> z) {
		t.zuhoererPlus(E_AENDERUNG, z);
	}

	public void eKnopfDeaktiv(S_Zuhoerer<TE_STYLE[]> z) {
		t.zuhoererPlus(E_KNOPF_DEAKTIV, z);
	}

	// SETZE

	/** @deprecated **/
	public void setze(TE_STYLE style) {
		wechsle(style);
	}

	public void sSchrift(SWT_SCHRIFT schrift, int groesse, SWT_SCHRIFTSTIL... stile) {
		this.editor.sSchrift(schrift, groesse, stile);
//		t.zuhoererStart(E_AENDERUNG);
	}

	public Boolean wechsle(TE_STYLE style) {
		Ausgabe.debug("wechsle", style);
		iDeaktivieren(style);
		return iStyle(style, SETZEN.WECHSELN, null, true);
	}

	public void setze(TE_STYLE style, boolean wert) {
		Ausgabe.debug("setze", style, wert);
		SETZEN s=wert ? SETZEN.SETZEN : SETZEN.AUFHEBEN;
		iStyle(style, s, null, true);
	}

	public void setze(TE_STYLE style, boolean wert, Point xy) {
		Ausgabe.debug("setze", style, wert);
		SETZEN s=wert ? SETZEN.SETZEN : SETZEN.AUFHEBEN;
		iStyle(style, s, xy, true);
	}

	public void setze(TE_STYLE style, boolean wert, Point xy, boolean event) {
		Ausgabe.debugDetail("setze", style, wert);
		SETZEN s=wert ? SETZEN.SETZEN : SETZEN.AUFHEBEN;
		iStyle(style, s, xy, event);
	}

	public Boolean gib(TE_STYLE style) {
		return iStyle(style, SETZEN.ABFRAGE, null, true);
	}

	public Boolean gib(TE_STYLE style, Point xy) {
		return iStyle(style, SETZEN.ABFRAGE, xy, true);
	}

	public void setze(StyleRange sr, TE_STYLE style, boolean wert) {
		S_TE_SetStyle s=this.styles.gib(style);
		s.setze(sr, wert);
	}

	// INTERN

	private Boolean iStyle(TE_STYLE style, SETZEN setzen, Point xy, boolean event) {
		Fehler.objekt.wenn_Null(style, setzen);
		S_TE_SetStyle set=styles.gib(style);
		if(xy==null)
			xy=editor.swt().getSelectionRange();
		S_Folge<StyleRange> ranges=gBereich(xy.x, xy.y);
		if(ranges.gLaenge()==0) //Style für neuen Text gewählt
			return null;
		boolean gesetzt=set.gesetzt(ranges.gib(1));

		if(setzen==SETZEN.ABFRAGE)
			return gesetzt;
		if((gesetzt==true && setzen==SETZEN.SETZEN) || (gesetzt==false && setzen==SETZEN.AUFHEBEN))
			return gesetzt;

		for(StyleRange range : ranges)
			set.setze(range, !gesetzt);
		editor.swt().replaceStyleRanges(xy.x, xy.y, (StyleRange[]) WandleFolge.zuArray(ranges));
		if(event)
			t.zuhoererStart(E_AENDERUNG); //Prüfen
		return !gesetzt;
	}

	private S_Folge<StyleRange> gBereich(int start, int laenge) {
		StyleRange[] bestand=editor.swt().getStyleRanges(start, laenge);
		S_Liste<StyleRange> erg=Liste.neu();
		int naechstePos=start;
		for(StyleRange b : bestand) {
			int bSta=b.start;
			int bEnd=b.start+b.length;
			if(naechstePos<b.start) {
				StyleRange styleRange = new StyleRange();
				styleRange.start = naechstePos;
				styleRange.length = bSta-naechstePos;
				erg.plus(styleRange);
//				Ausgabe.debug("Neu1: "+start+"/"+laenge+"  > "+styleRange.start+"/"+styleRange.length+" "+styleRange);
			}
			erg.plus(b);
			naechstePos=bEnd;
		}
		if(naechstePos<start+laenge) {
			StyleRange styleRange = new StyleRange();
			styleRange.start = naechstePos;
			styleRange.length = start+laenge-naechstePos;
			erg.plus(styleRange);
//			Ausgabe.debug("Neu2: "+start+"/"+laenge+"  > "+styleRange.start+"/"+styleRange.length+" "+styleRange);
		}
//		Ausgabe.debug("Bereich ("+start+"/"+laenge+"):",erg);
		return erg;
	}

	private S_SchluesselListe<TE_STYLE, S_TE_SetStyle> iRegistrieren() {
		SchluesselListe<TE_STYLE, S_TE_SetStyle> erg=SchluesselListe.neu();

		erg.plus(TE_STYLE.FETT, new S_TE_SetStyle(){
			public boolean gesetzt(StyleRange sr) {
				return Mathe.bitsGesetzt(sr.fontStyle, SWT.BOLD);
			}
			public void setze(StyleRange sr, boolean setzen) {
				sr.fontStyle = setzen
					? Mathe.bitsSetzen(sr.fontStyle, SWT.BOLD)
					: Mathe.bitsLoeschen(sr.fontStyle, SWT.BOLD);
			}
		});

		erg.plus(TE_STYLE.UNTERSTRICHEN, new S_TE_SetStyle(){
			public boolean gesetzt(StyleRange sr) {
				return sr.underline && sr.underlineStyle==SWT.UNDERLINE_SINGLE && sr.font==null; //Achtung: Letzten Punkt bei Änderungen beachten!
			}
			public void setze(StyleRange sr, boolean setzen) {
				sr.underline=setzen;
				sr.underlineStyle=setzen
					? SWT.UNDERLINE_SINGLE
					: SWT.NONE;
			}
		});

		erg.plus(TE_STYLE.UEBERSCHRIFT, new S_TE_SetStyle(){
			public boolean gesetzt(StyleRange sr) {
				if(sr.font==null || sr.font.getFontData()==null || sr.font.getFontData().length==0)
					return false;
				FontData fd=sr.font.getFontData()[0];
				boolean b1=sr.underline;
				boolean b2=sr.underlineStyle==SWT.UNDERLINE_SINGLE;
//				boolean b3=Mathe.bitsGesetzt(sr.fontStyle, SWT.BOLD);
				boolean b4=fd.getHeight()==14;
				boolean b5=fd.getStyle()==SWT.BOLD;
				return b1 && b2 && b4 && b5;
			}
			public void setze(StyleRange sr, boolean setzen) {
				sr.underline=setzen;
				if(setzen)
					sr.underlineStyle=SWT.UNDERLINE_SINGLE;
//				sr.fontStyle = setzen
//					? Mathe.bitsSetzen(sr.fontStyle, SWT.BOLD)
//					: Mathe.bitsLoeschen(sr.fontStyle, SWT.BOLD);
				sr.font= setzen
					? SchriftManager.gSchrift(Display.getCurrent(), SWT_SCHRIFT.STANDARD, 14, SWT_SCHRIFTSTIL.FETT)
					: null;
			}
		});

//		public Boolean sDoppeltUnterstrichen() {
//			return style(new S_TE_SetStyle(){
//				public boolean gesetzt(StyleRange sr) {
//					return sr.underline && sr.underlineStyle==SWT.UNDERLINE_DOUBLE;
//				}
//				public void setze(StyleRange sr, boolean setzen) {
//					sr.underline=setzen;
//					if(setzen)
//						sr.underlineStyle=SWT.UNDERLINE_DOUBLE;
//				}
//			});
//		}

		erg.plus(TE_STYLE.KURSIV, new S_TE_SetStyle(){
			public boolean gesetzt(StyleRange sr) {
				return Mathe.bitsGesetzt(sr.fontStyle, SWT.ITALIC);
			}
			public void setze(StyleRange sr, boolean setzen) {
				sr.fontStyle = setzen ? Mathe.bitsSetzen(sr.fontStyle, SWT.ITALIC) : Mathe.bitsLoeschen(sr.fontStyle, SWT.ITALIC);
			}
		});

		erg.plus(TE_STYLE.DURCHGESTRICHEN, new S_TE_SetStyle(){
			public boolean gesetzt(StyleRange sr) {
				return sr.strikeout;
			}
			public void setze(StyleRange sr, boolean setzen) {
				sr.strikeout=setzen;
			}
		});

		return erg;
	}

	private void iDeaktivieren(TE_STYLE style) {
		if(MN.oder(style, TE_STYLE.FETT, TE_STYLE.KURSIV, TE_STYLE.UNTERSTRICHEN, TE_STYLE.DURCHGESTRICHEN)) {
			setze(TE_STYLE.UEBERSCHRIFT, false);
			t.zuhoererStart(E_KNOPF_DEAKTIV, new TE_STYLE[] {TE_STYLE.UEBERSCHRIFT});
		}
		else {
			setze(TE_STYLE.FETT, false);
			setze(TE_STYLE.KURSIV, false);
			setze(TE_STYLE.UNTERSTRICHEN, false);
			setze(TE_STYLE.DURCHGESTRICHEN, false);
			t.zuhoererStart(E_KNOPF_DEAKTIV, new TE_STYLE[] {TE_STYLE.FETT, TE_STYLE.KURSIV, TE_STYLE.UNTERSTRICHEN, TE_STYLE.DURCHGESTRICHEN});
		}
	}
}
